#pragma once 

#include"LockGuard.hpp"
#include<vector>
#include<string>
#include<memory>
#include<functional>
#include<unistd.h>
#include<pthread.h>
#include"Task.hpp"
#include"Thread.hpp"
#include"BlockingQueue.hpp"

namespace wbj
{
#define THREAD_NUM 10

    template class<T>
    class ThreadPool
    {
    private:
        ThreadPool(int num=THREAD_NUM)
        :_num(num)
        {}
        
        ~ThreadPool()
        {
            for(auto& t:_threads)
            {
                t.join();
            }
        }

        ThreadPool(const ThreadPool<T>& )=delete

    public:
            static ThreadPool<T>* getInstance()
            {
                if(_inst==nullptr)
                {
                    LockGuard lock(&_mtx);
                    if(_inst==nullptr)
                    {
                        //创建对象
                        _inst=new ThreadPool<T>();

                        //初始化启动服务
                        _inst->init();
                        _inst->start();
                    }
                }
                return _inst;
            }

        void init()
        {
            for(int i=0;i<_num;i++)
            _thread.push_back(Thread(i,threadRoutine,this));
        }

        void start()
        {
            for(auto &t:_threads)
            t.run();
        }

        static void threadRoutine(void* args)
        {
            pthread_detach(pthread_self());

            auto ptr=static_cast<ThreadPool<T>*>(args);

            while(true)
            {
                T task=ptr->popTask();

                task();
            }
        }

        void pushTask(const T& task)
        {
            _blockqueue.Push(task);
        }

    protected:
        T popTask()
        {
            T task;
            _blockqueue.Pop(&task);

            return task;
        }

    private:
        std::vector<Thread> _threads;//存储线程    
        int _num;//线程数
        BlockQueue<T> _blockqueue;//阻塞队列

        //创建静态单例对象指针及互斥锁
        static ThreadPool<T> *_inst;
        static pthread_mutex_t _mtx;
    };

    template<class T>
    ThreadPool<T>* ThreadPool<T>::_inst=nullptr;

    template<class T>
    pthread_mutex_t ThreadPool<T>::_mtx=PTHREAD_MUTEX_INITIALIZER;
}